#ifndef COMBINATORY_OBS_H
#define COMBINATORY_OBS_H

#include "aso-core/common_types.h"
#include "aso-core/generate_policy.h"
#include "aso-core/combinatory_policy.h"
#include "aso-core/antiviral_set.h"

/*! Definicion de MutantObs */
struct MutantObs
{
    const AntiviralSet   antivirals;      //! antivirales que produjeron las mutantes
    const SequenceSet    sequences;       //! sequencias de las mutantes
    const DistanceValue  distance;        //! distancia de mutación
    const ChildId        parent;          //! nodo del cual evolucionaron las mutantes

    /*! Constructor de MutantObs */
    MutantObs(const AntiviralSet& antivirals, const SequenceSet& sequences, DistanceValue distance, const ChildId& parent):
        antivirals(antivirals), sequences(sequences), distance(distance), parent(parent)
    {}
};

/*! Implementación de un observer de combinaciones */
class CombinationObserverImp: public CombinationObserver
{
public:
    //! Constructor
    CombinationObserverImp(biopp::PseudoNucSequence sequence, const ChildId& parentNode, Observer<MutantObs>* observer)
        : sequence(sequence), observer(observer), parentNode(parentNode)
    {}

private:
    biopp::PseudoNucSequence sequence;           //! virus base
    Observer<MutantObs>* observer;  //! grupo de observadores
    const ChildId parentNode;

    /*! Actualizar el Observador de Combinaciones */
    inline bool update(const Avs* comb);
};


bool CombinationObserverImp::update(const Avs* comb)
{
    MutantDist mutation;
    ResisBasedAntiviral antiviralComb("Comb", 0, tComb, cComb);
    AntiviralSet aux;
    aux.antivirals = *comb;
    aux.combine_set(antiviralComb);
    antiviralComb.mutate_sequence(sequence, mutation);
    /*! notifica la creacion de un nuevo grupo de mutantes */
    observer->update(new MutantObs(aux, mutation.sequences, mutation.distance, parentNode));
    return true;
}

#endif
